#include "task.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

std::vector<task_t> tasks; 
const int processnum = 10;

void slaver()
{
    // read(0)
    while(true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int)); // 如果父进程不给子进程发送数据呢？？阻塞等待！
        if(n == sizeof(int))
        {
            //执行cmdcode对应的任务列表
            std::cout <<"slaver say@ " << " I am " << getpid() <<" get a command , cmdcode: " <<  cmdcode << std::endl;
            if(cmdcode >= 0 && cmdcode < tasks.size()) tasks[cmdcode]();
        }
        if(n == 0) break;
    }
}

// 先描述
class channel
{
public:
    channel(int cmdfd, int slaverid, const std::string &processname)
    :_cmdfd(cmdfd), _slaverid(slaverid), _processname(processname)
    {}
public:
    int _cmdfd;               // 发送任务的文件描述符
    pid_t _slaverid;          // 子进程的PID
    std::string _processname; // 子进程的名字 -- 方便我们打印日志
};

void InitChannels(std::vector<channel>* channels)
{
    std::vector<int> oldfds;
    loadTask(&tasks);
    for(int i = 0; i < processnum; i++)
    {
        //创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        if(n != 0) // pipe error
            return;
        
        
        pid_t id = fork();  // 创建子进程
        if(id == 0) // child
        {
            for(int fd : oldfds) close(fd); // 关闭历史上父进程维护的管道文件的读端
            close(pipefd[1]); //关闭写端
            dup2(pipefd[0], 0);
            slaver(); // 执行任务
            //清理退出
            std::cout << "process : " << getpid() << " quit" << std::endl;
            exit(0);
        }

        //father
        close(pipefd[0]); // 关闭读端

        //子进程添加channel字段
        std::string name = "process - " + std::to_string(i);
        channels->push_back(channel(pipefd[1],id, name));
        oldfds.push_back(pipefd[1]); // 将对应子进程管道读端的文件描述符添加进vector
    }
}

void ctrlSle(const std::vector<channel> &channels)
{
    //轮转选择
    int witch = 0;
    int cnt = 7;

    while(cnt)
    {
        //选择任务
        int cmdcode = rand() % tasks.size();

        //选择进程
        //通过随机数选择进程以达到均衡调度的效果
        //int processpos = rand() % channels.size();

        //输出信息提示
        std::cout << "father say@ cmdcode : " << cmdcode 
        << " already sendto " << channels[witch]._slaverid << " process name : "
        << channels[witch]._processname << std::endl;

        //发送任务
        write(channels[witch]._cmdfd, &cmdcode, sizeof(cmdcode));  

        //维护计数器，保证轮询
        witch++;
        witch %= channels.size();
        
        cnt--;
        sleep(1); 
    }
}

void quitProc(const std::vector<channel> &channels)
{
    for(const auto &c : channels)
    { 
        close(c._cmdfd);
        waitpid(c._slaverid, nullptr, 0);
    }
    // for(const auto &c : channels) close(c._cmdfd);
    // sleep(5);
    // for(const auto &c : channels) waitpid(c._slaverid, nullptr, 0);
    // // sleep(5);
}

int main()
{ 
    //种一棵随机数种子
    srand(time(nullptr) ^ getpid() ^ 1024);

    //再组织
    std::vector<channel> channels;
    
     
    //1、初始化
    InitChannels(&channels);
    
    //2、控制子进程
    ctrlSle(channels);
    
    //3、退出清理
    quitProc(channels);

    return 0;
}